using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;


namespace ebookreader
{
    public abstract class Menu : DrawableGameComponent
    {
        #region Fields

        protected SpriteBatch sprite_batch;

        protected List<MenuEntry> entries;
        protected List<RenderableObject> renderables;
        public IInputManager input_manager { get; private set; }
        public bool enabledInput = true;
        public bool enableUpdate = true;
        public Rectangle area;
        public Rectangle scrollable_area;
        public bool disableNotContainedElement = true;
        public bool enableHorizzontalDrag = false;
        public bool enableVerticalDrag = true;

        private bool addedInputManager = false;
        #endregion

        public Menu(Game game, Rectangle area, IInputManager input_manager)
            : base(game)
        {
            entries = new List<MenuEntry>();
            renderables = new List<RenderableObject>();
            this.area = area;
            this.scrollable_area = area;

            this.input_manager = input_manager;
            if (input_manager == null)
            {
                this.input_manager = new InputManager(game);
                addedInputManager = true;
                for (int i = 0; i < Game.Components.Count; i++)
                    if (Game.Components[i] is InputManager)
                        (Game.Components[i] as InputManager).Active = false;
                Game.Components.Add((IGameComponent)this.input_manager);
            }
            

        }

        public Menu(Game game, Rectangle area)
            : this(game, area, new InputManager(game))
        {
            addedInputManager = true;
            for (int i = 0; i < Game.Components.Count; i++)
                if (Game.Components[i] is InputManager)
                    (Game.Components[i] as InputManager).Active = false;
            Game.Components.Add((IGameComponent)input_manager);
        }

        public Menu(Game game, IInputManager input_manager)
            : this(game, game.GraphicsDevice.Viewport.Bounds, input_manager)
        { }

        public Menu(Game game)
            : this(game, game.GraphicsDevice.Viewport.Bounds)
        { }

        public void OnTap(Vector2 tap_position)
        {
            if (dragging || !enabledInput || !input_manager.Active)
                return;
            for (int i = 0; i < entries.Count; i++)
            {
                var e = entries[i];
                var rect = e.rectangle;
                rect.Offset((int)e.scrollOffset.X, (int)e.scrollOffset.Y);
                //rect.Location = new Point(rect.Location.X + (int)e.scrollOffset.X, rect.Location.Y + (int)e.scrollOffset.Y);
                if ( e.active &&(area.Contains(rect) || !disableNotContainedElement))
                    entries[i].OnTap(tap_position - (entries[i].scrollable?offsetPosition:Vector2.Zero) );                
            }
        }

        public void OnDoubleTap(Vector2 tap_position)
        {
            if (dragging || !enabledInput || !input_manager.Active)
                return;
            for (int i = 0; i < entries.Count; i++)
            {
                var e = entries[i];
                var rect = e.rectangle;
                rect.Offset((int)e.scrollOffset.X, (int)e.scrollOffset.Y);
                //rect.Location = new Point(rect.Location.X + (int)e.scrollOffset.X, rect.Location.Y + (int)e.scrollOffset.Y);
                if (e.active && (area.Contains(rect) || !disableNotContainedElement))
                    entries[i].OnDoubleTap(tap_position - (entries[i].scrollable ? offsetPosition : Vector2.Zero));
            }
        }


        public void OnHold(Vector2 press_position)
        {
            if (dragging || !enabledInput|| !input_manager.Active)
                return;

         

            for (int i = 0; i < entries.Count; i++)
            {
                var e = entries[i];
                var rect = e.rectangle;
                rect.Offset((int)e.scrollOffset.X, (int)e.scrollOffset.Y);
                //rect.Location = new Point(rect.Location.X + (int)e.scrollOffset.X, rect.Location.Y + (int)e.scrollOffset.Y);
                if (e.active && (area.Contains(rect) || !disableNotContainedElement))
                    entries[i].OnHold(press_position - (entries[i].scrollable ? offsetPosition : Vector2.Zero));
            }
        }

        bool initializeIM = false;
        //static SoundEffect button_sound;
        public override void Initialize()
        {
            
            //input_manager = Game.Services.GetService(typeof(IInputManager)) as IInputManager;
            //input_manager = Game.Services.GetService(typeof(IInputManager)) as IInputManager;
            //if (input_manager == null)
            //{
            //    initializeIM = true;
            //    Game.Components.Add(new InputManager(Game));
            //    input_manager = Game.Services.GetService(typeof(IInputManager)) as IInputManager;
            //}
            input_manager.OnHorizontalDrag += new InputManager.Drag(OnDrag);
            input_manager.OnVerticalDrag += new InputManager.Drag(OnDrag);
            input_manager.OnDragCompleted += new InputManager.DragCompleted(OnDragCompleted);

            

            base.Initialize();
        }
               

        protected override void Dispose(bool disposing)
        {
            //if (input_manager != null && initializeIM)
            //    input_manager.OnDragCompleted -= new InputManager.DragCompleted(OnDragCompleted);
            //Game.Services.RemoveService(typeof(IInputManager));

            if (addedInputManager)
            {
                Game.Components.Remove((IGameComponent)input_manager);
                for (int i = Game.Components.Count-1; i>=0; i--)
                    if (Game.Components[i] is InputManager)
                    {
                        (Game.Components[i] as InputManager).Active = true;
                        break;
                    }
            }
            base.Dispose(disposing);
        }

        
        protected Vector2 offsetPosition = Vector2.Zero;
        public override void Update(GameTime gameTime)
        {

            if (!enableUpdate)
                return;
            if (dragging)
            {
                offsetPosition.X += enableHorizzontalDrag?forceX:0;
                offsetPosition.Y += enableVerticalDrag?forceY:0;
            }
            for (int i = 0; i < entries.Count; i++)
            {
                var e = entries[i];
                if (e == null) break;

                if (e == null || e.position.Y + offsetPosition.Y < -1000 || e.position.Y + offsetPosition.Y > 1500)
                    continue;

                e.scrollOffset = offsetPosition;

                if (e.rectangle.Contains(input_manager.getFirstTouchLoacatiopn()) && enabledInput)
                    e.touched = true;
                else
                    e.touched = false;


                //var rect = e.rectangle;
                //rect.Location = new Point(rect.Location.X + (int)e.scrollOffset.X, rect.Location.Y + (int)e.scrollOffset.Y);
                //if (area.Contains(rect))
                //    e.active = true;
                //else
                //    e.active = false;

            }
           
            //offsetPosition = Vector2.Zero;
            base.Update(gameTime);
        }

        public override void  Draw(GameTime gameTime)
        {
            //GraphicsDevice.Clear(Color.CornflowerBlue);

            sprite_batch.Begin();

            for (int i = 0; i < renderables.Count; i++)
            {
                renderables[i].Draw();
            }

            for (int i = 0; i < entries.Count; i++)
            {
                var e = entries[i];
                
                if (e == null || e.position.Y + e.scrollOffset.Y < -1000 || e.position.Y + e.scrollOffset.Y > 1500)
                    continue;
                //var pos = new Vector2(e.position.Y + e.scrollOffset.Y, e.position.Y + e.scrollOffset.Y);

                //if (e.scrollOffset.Y + e.position.Y < 1480 && entries[i].scrollOffset.Y + e.position.Y > -1000)
                //    entries[i].DrawInsideSpriteBatch();               
                
                var rect = e.rectangle;
                rect.Offset((int)e.scrollOffset.X, (int)e.scrollOffset.Y);
                //rect.Location = new Point(rect.Location.X+(int)e.scrollOffset.X, rect.Location.Y + (int)e.scrollOffset.Y);
                if(area.Intersects(rect))
                    entries[i].DrawInsideSpriteBatch(); 
            }

            //var fps = 1 / gameTime.ElapsedGameTime.TotalSeconds;
            //sprite_batch.DrawString(Game.Content.Load<SpriteFont>("Fonts/Arial"), "" + fps, new Vector2(700, 10), Color.Red);
            //sprite_batch.Draw(Game.Content.Load<Texture2D>("Textures/UI/BookList/date_box"), area, Color.White);


            //if (GC.GetTotalMemory(false) < last_gc_size)
            //{
            //    time_from_last_gc = last_gc_delta;
            //    last_gc_delta = 0;
            //    num_collects++;
            //}
            //last_gc_delta += (float)gameTime.ElapsedGameTime.TotalSeconds;
            //last_gc_size = GC.GetTotalMemory(false);

            //sprite_batch.DrawString(font, time_from_last_gc + "\n" + last_gc_delta +"\n"+num_collects, Vector2.Zero, Color.Red);
            //sprite_batch.DrawString(font, "" + (1 / gameTime.ElapsedGameTime.TotalSeconds), Vector2.UnitX * 700, Color.Red);
            sprite_batch.End();
            
 	        base.Draw(gameTime);
        }
        int num_collects = 0;
        long last_gc_size = 0;
        float time_from_last_gc = 0;
        float last_gc_delta=0;
        SpriteFont font;
        protected override void LoadContent()
        {
            font = Game.Content.Load<SpriteFont>("Fonts/menu");
            if (MenuEntry.press_sound == null)
                MenuEntry.press_sound = Game.Content.Load<SoundEffect>("Sound/button");
            base.LoadContent();
        }
       
        Vector2 lastDrag;
        protected float forceY = 0, forceX=0;
        void OnDrag(Vector2 delta)
        {
            if (!enabledInput|| !input_manager.Active) return;
            if (!dragging)
            {
                lastDrag = delta;
                Game.TargetElapsedTime = TimeSpan.FromSeconds(1 / 30.0f);
                if (!scrollable_area.Contains((int)lastDrag.X, (int)lastDrag.Y))
                    return;
            }

            dragging = true;
            forceY = (delta - lastDrag).Y;
            forceX = (delta - lastDrag).X;
            //offsetPosition += Vector2.UnitY * force;
            lastDrag = delta;
        }


        protected bool dragging = false;
        void OnDragCompleted()
        {
            dragging = false;
        }
    }
}
